﻿open System
open System.Collections.Generic
type Calc = | Add | Subtract

(* Alias MailboxProcessor with Agent *)
type Agent<'a> = MailboxProcessor<'a>
//type AgentCommands = | Kill 

let registry = new Dictionary<string,Object>()



let createWorker (f :'a->unit) = 
    let pid = Guid.NewGuid().ToString()
    let nAgent = new Agent<'a>(fun inbox ->
                let rec loop message = async {
                    let! message = inbox.Receive()
                    f message
                    return! loop() }
                loop())
    pid,nAgent

let associateWorkerWithRegistry (pid,worker: Agent<'a>) = 
    match registry.ContainsKey(pid) with
        | true -> 
            let agent = registry.[pid]
            worker.Start()
            registry.[pid] <- worker
            pid 
        | false ->
            worker.Start()
            registry.Add(pid,worker)
            pid


(* Spawn Worker *)
let spawn (f :'a->unit) = (createWorker >> associateWorkerWithRegistry) f

let special_spawn f =
    match f with
    | func when func.GetType() = typeof<'a->unit> -> (createWorker >> associateWorkerWithRegistry) f
    | func when func.GetType() = typeof<'a->'b->unit> -> (createWorker >> associateWorkerWithRegistry) f
    | _ -> failwith "Not Supported"


(* Post Msg To Worker *)        
let (!) a b = 
            match registry.ContainsKey(a) with
            | true -> 
                let agent = registry.[a] :?> Agent<'a>
                agent.Post(b)
            | false -> ()
                
(* Kill all Workers *)
let kill_all = registry.Clear()
// -----------------------------------------------------------



let v = spawn( fun msg ->
                   match msg with
                   | Add -> printfn "%s \n" "Add"
                   | Subtract -> printfn "%s \n" "Subtract" )

! v Add
            